package com.softgroup.breath.easyecgproject.service;

import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;

import com.softgroup.breath.easyecgproject.entry.CommandInfo;
import com.softgroup.breath.easyecgproject.myapi.FormatCast;
import com.softgroup.breath.easyecgproject.myapi.RequistCommand;
import com.softgroup.breath.easyecgproject.utils.DataManager;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.InetSocketAddress;
import java.net.Socket;


/**
 * Created by Administrator on 2017/5/19.
 */

public class BluetoothLeService extends Service {
    private final static String TAG = BluetoothLeService.class.getSimpleName();
    private BluetoothManager mBluetoothManager;
    private BluetoothAdapter mBluetoothAdapter;

    public String getmBluetoothDeviceAddress() {
        return mBluetoothDeviceAddress;
    }

    private String mBluetoothDeviceAddress;
    private BluetoothGatt mBluetoothGatt;
    private BluetoothDevice mBluetoothDevice;
    private OnLeScanListener mOnLeScanListener;
    private int mConnectionState = STATE_DISCONNECTED;
    private static final long SCAN_PERIOD = 20 * 1000;
    private static final int STATE_DISCONNECTED = 0;
    private static final int STATE_CONNECTING = 1;
    private static final int STATE_CONNECTED = 2;

    private static final String HOST = "182.92.106.31";
    private static final int PORT = 7478;
    private Socket socket = null;
    private BufferedReader in = null;
    private PrintStream out = null;


    private InetSocketAddress endpoint = new InetSocketAddress(HOST, PORT);
    private String phoneId;

    public final static String ACTION_GATT_CONNECTED = "com.bairuisheng.wxj.jsondemo.ACTION_GATT_CONNECTED";
    public final static String ACTION_GATT_DISCONNECTED = "com.bairuisheng.wxj.jsondemo.ACTION_GATT_DISCONNECTED";
    public final static String ACTION_GATT_SERVICES_DISCOVERED = "com.bairuisheng.wxj.jsondemo.ACTION_GATT_SERVICES_DISCOVERED";
    public final static String ACTION_DATA_AVAILABLE = "com.bairuisheng.wxj.jsondemo.ACTION_DATA_AVAILABLE";
    public final static String ACTION_GATT_RSSI = "com.bairuisheng.wxj.jsondemo.ACTION_GATT_RSSI";
    public final static String ACTION_SCAN_FINISHED = "com.bairuisheng.wxj.jsondemo.ACTION_SCAN_FINISHED";
    public final static String EXTRA_DATA = "com.bairuisheng.wxj.jsondemo.EXTRA_DATA";
    public final static String EXTRA_RSSI = "com.bairuisheng.wxj.jsondemo.EXTRA_RSSI";
    public final static String ACTION_SOCKET_CALLBACK = "com.bairuisheng.wxj.jsondemo.ACTION_SOCKET_CALLBACK";
    public final static String EXTRA_CALLBACK = "com.bairuisheng.wxj.jsondemo.EXTRA_CALLBACK";
    public final static String EXTRA_NETWORK_CONNECT_FAILED = "com.bairuisheng.wxj.jsondemo.EXTRA_NETWORK_CONNECT_FAILED";

    private boolean isKeepConnect = true;
    private BluetoothGattCharacteristic bluetoothGattCharacteristicWrite;
    private BluetoothGattCharacteristic bluetoothGattCharacteristicRead;
    private boolean isScanning;
    private long breakTime;
    private DataManager dataManager;


    public void timerTask() {
        if (isKeepConnect) {
            if (initialize() && mBluetoothAdapter.isEnabled() && mBluetoothGatt != null && mConnectionState == BluetoothLeService.STATE_DISCONNECTED) {
                mBluetoothGatt.connect();
            }
        }
        if (mConnectionState == BluetoothLeService.STATE_CONNECTED) {
//            mBluetoothGatt.readRemoteRssi();
        }
        if (isKeepConnect && mConnectionState == STATE_DISCONNECTED && mBluetoothGatt != null && System.currentTimeMillis() - breakTime > 1000) {
            mBluetoothManager = null;
            mBluetoothAdapter = null;
            if (initialize()) {
                enableBluetooth(true);
                if (mBluetoothAdapter.isEnabled()) {
                    mBluetoothGatt.close();
                    mBluetoothGatt = null;
                    connect(mBluetoothDeviceAddress);
                }
            }
        }
    }

    // Implements callback methods for GATT events that the app cares about.  For example,
    // connection change and services discovered.
    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            String intentAction;
            breakTime = System.currentTimeMillis();
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                intentAction = ACTION_GATT_CONNECTED;
                mConnectionState = STATE_CONNECTED;
                broadcastUpdate(intentAction);
                Log.i(TAG, "Connected to GATT server.");
                // Attempts to discover services after successful connection.
                Log.i(TAG, "Attempting to start service discovery:" +
                        mBluetoothGatt.discoverServices());
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                intentAction = ACTION_GATT_DISCONNECTED;
                mConnectionState = STATE_DISCONNECTED;
                Log.i(TAG, "Disconnected from GATT server.");
                broadcastUpdate(intentAction);
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
            } else {
                Log.w(TAG, "onServicesDiscovered received: " + status);
            }
            try {
                bluetoothGattCharacteristicWrite = gatt.getService(RequistCommand.UUID_SERVICE).getCharacteristic(RequistCommand.UUID_DATA_SEND);
                bluetoothGattCharacteristicRead = gatt.getService(RequistCommand.UUID_SERVICE).getCharacteristic(RequistCommand.UUID_DATA_RECEIVE);
                setCharacteristicNotification(bluetoothGattCharacteristicRead, true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt,
                                         BluetoothGattCharacteristic characteristic,
                                         int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
//                dataManager.writeDataManager(characteristic.getValue());
//                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
            }
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt,
                                            BluetoothGattCharacteristic characteristic) {
//            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
//            broadCastUpdate(ACTION_SOCKET_CALLBACK,bytesToHexString(characteristic.getValue()));
            dataManager.writeDataManager(characteristic.getValue());
        }

        @Override
        public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
            super.onReadRemoteRssi(gatt, rssi, status);
//            Log.w(TAG, "onReadRemoteRssi received: " + rssi);
            broadCastUpdate(ACTION_GATT_RSSI, rssi);
        }
    };

    private void broadcastUpdate(final String action) {
        final Intent intent = new Intent(action);
        sendBroadcast(intent);
    }

    private void broadcastUpdate(final String action,
                                 final BluetoothGattCharacteristic characteristic) {
        final Intent intent = new Intent(action);
        final byte[] data = characteristic.getValue();
        intent.putExtra(EXTRA_DATA, data);
        sendBroadcast(intent);
    }

    private void broadCastUpdate(final String action, final int rssi) {
        final Intent intent = new Intent(action);
        intent.putExtra(EXTRA_RSSI, rssi);
        sendBroadcast(intent);
    }

    private void broadCastUpdate(final String action, final String callback) {
        final Intent intent = new Intent(action);
        intent.putExtra(EXTRA_CALLBACK, callback);
        sendBroadcast(intent);
    }

    public class LocalBinder extends Binder {
        public BluetoothLeService getService() {
            return BluetoothLeService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        dataManager = DataManager.getInstance();
    }

    public boolean initialize() {
        // For API level 18 and above, get a reference to BluetoothAdapter through
        // BluetoothManager.
        if (mBluetoothManager == null) {
            mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
            if (mBluetoothManager == null) {
                Log.e(TAG, "Unable to initialize BluetoothManager.");
                return false;
            }
        }
        mBluetoothAdapter = mBluetoothManager.getAdapter();
        if (mBluetoothAdapter == null) {
            Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
            return false;
        }
        return true;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        close();
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        try {
            if (socket != null)
                socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        super.onDestroy();
    }

    private final IBinder mBinder = new LocalBinder();


    public boolean enableBluetooth(boolean enable) {
        if (enable) {
            if (!mBluetoothAdapter.isEnabled()) {
                return mBluetoothAdapter.enable();
            }
            return true;
        } else {
            if (mBluetoothAdapter.isEnabled()) {
                return mBluetoothAdapter.disable();
            }
            return false;
        }
    }

    public boolean isEnableBluetooth() {
        return mBluetoothAdapter.isEnabled();
    }


    public void scanLeDevice(final boolean enable, long scanPeriod) {
        if (enable) {
            if (isScanning) return;
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    isScanning = false;
                    mBluetoothAdapter.stopLeScan(mScanCallback);
                    broadcastUpdate(ACTION_SCAN_FINISHED);
                }
            }, scanPeriod);
            isScanning = true;
            mBluetoothAdapter.startLeScan(mScanCallback);
        } else {
            isScanning = false;
            mBluetoothAdapter.stopLeScan(mScanCallback);
            broadcastUpdate(ACTION_SCAN_FINISHED);
        }
    }

    private final BluetoothAdapter.LeScanCallback mScanCallback = new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
            if (mOnLeScanListener != null) {
                mOnLeScanListener.onLeScan(device, rssi, scanRecord);
            }
        }

    };

    public void scanLeDevice(boolean enable) {
        this.scanLeDevice(enable, SCAN_PERIOD);
    }

    public boolean isScanning() {
        return isScanning;
    }

    public boolean connect(final String address) {
        if (mBluetoothAdapter == null || address == null) {
            Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
            return false;
        }
        if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
                && mBluetoothGatt != null) {
            Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
            if (mBluetoothGatt.connect()) {
                mConnectionState = STATE_CONNECTING;
                return true;
            } else {
                return false;
            }
        }
        mBluetoothDevice = null;
        mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(address);
        if (mBluetoothDevice == null) {
            Log.w(TAG, "Device not found.  Unable to connect.");
            return false;
        }
        if (mBluetoothGatt != null) {
            mBluetoothGatt.disconnect();
            mBluetoothGatt.close();
            mBluetoothGatt = null;
        }
        mBluetoothGatt = mBluetoothDevice.connectGatt(this, false, mGattCallback);
        Log.d(TAG, "Trying to create a new connection.");
        mBluetoothDeviceAddress = address;
        mConnectionState = STATE_CONNECTING;
        return true;
    }

    public void disconnect() {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
            return;
        }
        mBluetoothGatt.disconnect();
    }

    public void reConnect() {
        if (initialize() & mBluetoothGatt != null) {
            mBluetoothGatt.connect();
        }
    }

    public void close() {
        if (mBluetoothGatt == null) {
            return;
        }
        mBluetoothGatt.close();
        mBluetoothGatt = null;
    }

    public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
            return;
        }
        mBluetoothGatt.readCharacteristic(characteristic);
    }

    public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
            return;
        }
        mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
        // This is specific to Heart Rate Measurement.
        if (RequistCommand.UUID_DATA_RECEIVE.equals(characteristic.getUuid())) {
            BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
                    RequistCommand.UUID_CLIENT_CHARACTERISTIC_CONFIG);
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            mBluetoothGatt.writeDescriptor(descriptor);
        }
    }

    public void setIsKeepConnect(boolean isKeepConnect) {
        this.isKeepConnect = isKeepConnect;
    }

    /*
     * 蓝牙写入数据
     * */
    public void writeCommand(int position) {
        if (mBluetoothGatt != null && mBluetoothGatt.readRemoteRssi() & bluetoothGattCharacteristicWrite != null) {
            bluetoothGattCharacteristicWrite.setValue(FormatCast.getHexBytes(CommandInfo.getRealQuest(position)));
            mBluetoothGatt.writeCharacteristic(bluetoothGattCharacteristicWrite);
            Log.e("device_command", CommandInfo.getRealQuest(position));
            broadCastUpdate(ACTION_SOCKET_CALLBACK, CommandInfo.getRealQuest(position));
        }
    }

    public void writeCommand(String quest) {
        if (mBluetoothGatt != null && mBluetoothGatt.readRemoteRssi() & bluetoothGattCharacteristicWrite != null) {
            bluetoothGattCharacteristicWrite.setValue(FormatCast.getHexBytes(quest));
            mBluetoothGatt.writeCharacteristic(bluetoothGattCharacteristicWrite);
            Log.e("device_command", quest);
            broadCastUpdate(ACTION_SOCKET_CALLBACK, quest);
        }
    }


    public void dataCallBack(final byte[] bytes) {
//        Log.e("TAG", bytes[106] + ">" + bytes[107]);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    socket = new Socket();
                    socket.connect(endpoint);
                    in = new BufferedReader(new InputStreamReader(socket
                            .getInputStream()));
                    out = new PrintStream(socket.getOutputStream(), true);
                    if (socket.isConnected()) {
                        broadCastUpdate(ACTION_SOCKET_CALLBACK, "连接成功");
                    }
                    if (socket.isConnected()) {
                        if (!socket.isOutputShutdown()) {
                            out.write(bytes);
                            int i = 0;
                            while (true) {
                                Thread.sleep(100);
                                String s = in.readLine();
                                if (s == null) {
                                    continue;
                                } else {
                                    break;
                                }
                            }
                        }
                    }

                } catch (Exception ex) {
                    ex.printStackTrace();
                    if (!socket.isConnected()) {
                        broadCastUpdate(ACTION_SOCKET_CALLBACK, EXTRA_NETWORK_CONNECT_FAILED);
                    }
                } finally {
                    if (socket != null) {
                        try {
                            out.close();
                            in.close();
                            socket.close();
                        } catch (Exception e) {
                            socket = null;
                        }
                    }
                }
            }
        }).start();
    }


    public interface OnLeScanListener {
        void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord);
    }

    public void setOnLeScanListener(OnLeScanListener l) {
        mOnLeScanListener = l;
    }
}